package JackAnalyzer;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;



public class JackTokenizer {

	private Scanner input;
	private String currentLine;
	private boolean moveLine;
	private String token;
	private int lineNum;

	private int tokenType;
	private String keyWord;
	private String symbol;
	private String identifier;
	private int intVal;
	private String stringVal;


	public JackTokenizer(File file){
		try {
			input = new Scanner(file);
			moveLine = true;
			lineNum = 0;
		} catch (FileNotFoundException e) {
			throw new RuntimeException("File name:" + file.getName() + " is not found");
		}
	}

	public String line(){
		return currentLine;
	}

	public int lineNum(){
		return lineNum;
	}

	public boolean hasMoreTokens(){

		while(input.hasNext()) {	
			if(moveLine){
				currentLine = input.nextLine().trim();
				lineNum++;
				moveLine = false;
			}

			if(currentLine.startsWith("//") || currentLine.isEmpty()){
				moveLine = true;
				continue;
			}


			if(currentLine.startsWith("/*")){
				while(!currentLine.contains("*/")){
					currentLine = input.nextLine().trim();
					lineNum++;
				}
				if(!input.hasNext())
					return false;
				currentLine = input.nextLine().trim();	
				lineNum++;
			}

			if(!currentLine.startsWith("//") && !currentLine.startsWith("/*") && !currentLine.isEmpty()){
				//currentLine = currentLine.split("//")[0].trim().split("//*")[0];
				return true;
			}
		}
		input.close();
		return false;
	}
	
	public void advance(){
		int beginCut = nextToken();
		currentLine = currentLine.substring(beginCut);
		if(currentLine == ""){
			moveLine = true;
		}
		if(JackAnalyzer.DEBUG_T)
			System.err.println(token);
		if(!currentLine.contains('"' + "")){

			currentLine = currentLine.split("//")[0].trim().split("///*")[0];

		}

		Integer type = JackData.Tokens.get(token);
		//KeyWord or Symbol
		if(type != null){
			tokenType = type;
			switch(tokenType){
			case JackData.KEYWORD:
				keyWord = token;
				//setTokenType(token);
				break;
			case JackData.SYMBOL:
				symbol = token;
				break;
			}
		}
		//Constant_Int or String
		else{
			if(JackData.isInt(token)){
				tokenType = JackData.INT_CONST;
				intVal = Integer.parseInt(token);
			}
			else{
				//Constant_String
				if(JackData.isStringConst(token)){
					tokenType = JackData.STRING_CONST;
					stringVal = token.replace("\"", "");
				}
				//Identifier
				else{
					tokenType = JackData.IDENTIFIER;
					identifier = token;
				}
			}
		}
	}

	private int nextToken(){
		currentLine = currentLine.trim();
		boolean isToken = false;
		token = "";
		int it = 0;
		while(!isToken){
			char ch = currentLine.charAt(it);
			Integer type = JackData.Tokens.get(ch + "");//the map is <String,Integer>

			boolean whiteSpace = Character.isWhitespace(ch);
			boolean symbolDetected = (type != null && (type == JackData.SYMBOL));

			if(it == 0 && ch =='\"'){
				if(JackAnalyzer.DEBUG)
					System.err.println(currentLine);
				do{
					if(currentLine.charAt(it) == '\\'){
						if(currentLine.charAt(it+1) == '\\'){
							token += currentLine.charAt(it);
							it++;
						}else if(currentLine.charAt(it+1) == '\"'){
							token += currentLine.charAt(it);
							it++;
						}
					}
					token += currentLine.charAt(it++);		
				}while(currentLine.charAt(it) != '\"');
				token += currentLine.charAt(it);

				it++;
				currentLine = currentLine.trim();
				isToken = true;
			}
			else{
				if(!whiteSpace && !symbolDetected){
					token += currentLine.charAt(it);
					it++;
					if(it == currentLine.length())
						isToken = true;
				}
				else{
					if(whiteSpace){
						while(Character.isWhitespace(currentLine.charAt(it))){
							it++;
						}
					}
					else if(symbolDetected){
						if(token.isEmpty()){
							token = ch+"";
							it++;
						}
					}
					isToken = true;
				}
			}
		}
		return it;
	}

	public int tokenType(){
		return tokenType;
	}

	public String keyWord(){
		return keyWord;
	}

	public String symbol(){
		return symbol;
	}

	public String identifier(){
		return identifier;
	}

	public int intVal(){
		return intVal;
	}

	public String stringVal(){
		return stringVal;
	}

	public boolean checkAndAdvance(){
		if(hasMoreTokens()){
			advance();
			return true;
		}
		throw new RuntimeException("EOF");
	}

	public String token(){
		switch (tokenType) {
		case JackData.KEYWORD: return keyWord;
		case JackData.SYMBOL: return symbol;
		case JackData.IDENTIFIER: return identifier;
		case JackData.INT_CONST: return intVal + "";
		case JackData.STRING_CONST: return stringVal;
		}
		return "N/A";
	}
}

